using System.Drawing;
using System.Windows.Forms;
using ApplicationGenerator.Forms.Utilities;
using ApplicationGenerator.Forms.WebControls;

namespace VisualEditorUILib
{
    public delegate void FormEditorPanelHandler(BaseControl bc);

    public partial class FormEditorPanel : TableLayoutPanel
    {

        #region Variables

        public event FormEditorPanelHandler fephEvent;
        private float columnWidth = 80F;
        private float rowHeight = 25F;
        private FormControlContainer formCContainer;
        private int selectedRow = 0;
        private int selectedColumn = 0;
        System.Windows.Forms.PropertyGrid pg = null;

        #endregion

        #region Constructors

        public FormEditorPanel(System.Windows.Forms.PropertyGrid _pg)
        {
            InitializeComponent();
            this.AllowDrop = true;
            pg = _pg;
            AddEventHandlers();

        }

        public FormEditorPanel(int numOfRows, int numOfColumns, System.Windows.Forms.PropertyGrid _pg)
        {
            InitializeComponent();
            InitializeComponentCustom(numOfRows, numOfColumns);
            pg = _pg;
            this.AllowDrop = true;
            AddEventHandlers();
        }

        public FormEditorPanel(FormControlContainer fcc)
        {
            InitializeComponent();
            InitializeComponentCustom(fcc.RowsCount, fcc.ColumnsCount);
            this.AllowDrop = true;
            formCContainer = fcc;
            UpdateLook();
            AddEventHandlers();
        }

        private void UpdateLook()
        {

            for (int row = 0; row < formCContainer.RowsCount; row++)
            {
                for (int col = 0; col < formCContainer.ColumnsCount; col++)
                {
                    BaseControl baseControl = null;
                    if (null != (baseControl = formCContainer.GetControl(row, col)))
                    {
                        //regenerate source!!!
                        if (baseControl is BaseMappedControl)
                        {
                            ((BaseMappedControl)baseControl).Source = formCContainer.Source;
                        }

                        Control ctrl = GControlFactory.Instance.GetControlFromDesignerTypeName(baseControl.GetType().FullName);
                        this.Controls.Add(ctrl, col, row);
                    }
                }
            }

        }

        /// <summary>
        /// initializes component
        /// </summary>
        /// <param name="numOfRows"> number of rows</param>
        /// <param name="numOfColumns">number of columns</param>
        private void InitializeComponentCustom(int numOfRows, int numOfColumns)
        {

            this.AutoSize = true;
            this.BackColor = System.Drawing.Color.White;
            this.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.Single;
            this.ColumnCount = numOfColumns;

            for (int i = 0; i < numOfColumns; i++)
            {
                this.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, columnWidth));
            }

            this.RowCount = numOfRows;

            for (int i = 0; i < numOfRows; i++)
            {
                this.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, rowHeight));
            }

            this.Size = new System.Drawing.Size((int)(numOfColumns * columnWidth), (int)(numOfRows * rowHeight));
        }


        #endregion

        #region Methods

        /// <summary>
        /// calculates row and column
        /// </summary>
        /// <param name="row"> ref row</param>
        /// <param name="column">ref column</param>
        /// <param name="e">MouseEventArgs to get x and y coords of mouse pointer</param>
        /// <returns></returns>
        private bool GetColAndRow(ref int row, ref int column, Point loc)
        {
            row = column = 0;
            int verticalOffset = 0;

            foreach (int h in this.GetRowHeights())
            {
                column = 0;
                int horizontalOffset = 0;

                foreach (int w in this.GetColumnWidths())
                {
                    Rectangle rectangle = new Rectangle(horizontalOffset, verticalOffset, w, h);
                    if (rectangle.Contains(loc))
                    {
                        return true;
                    }
                    horizontalOffset += w;
                    column++;
                }

                verticalOffset += h;
                row++;

            }

            return false;
        }

        /// <summary>
        /// Adds event handlers for this control
        /// </summary>
        private void AddEventHandlers()
        {
            this.MouseClick += new MouseEventHandler(Form_CellClicked);
            this.DragDrop += new System.Windows.Forms.DragEventHandler(Form_DragDrop);
            this.DragEnter += new System.Windows.Forms.DragEventHandler(Form_DragEnter);
            this.CellPaint += new System.Windows.Forms.TableLayoutCellPaintEventHandler(Form_CellPaint);
        }

        /// <summary>
        /// Removes control from FormControlContainer and from its this control
        /// </summary>
        public void RemoveSelectedField()
        {
            Control ctrl = this.GetControlFromPosition(selectedColumn, selectedRow);
            this.Controls.Remove(ctrl);
            formCContainer.RemoveControl(selectedRow, selectedColumn);
            this.UpdateLook();
        }

        #endregion

        #region Event handlers

        /// <summary>
        /// Handles DragEnter event and recognizes data type sent by sender
        /// </summary>
        /// <param name="sender"> sender of event </param>
        /// <param name="e"> event arguments </param>
        private void Form_DragEnter(object sender, DragEventArgs e)
        {
            //As we are interested in Type data only 
            //we will check this as follows
            if (e.Data.GetDataPresent(typeof(string)))
            {
                e.Effect = DragDropEffects.Copy;
            }
            else
            {
                e.Effect = DragDropEffects.None;
            }
        }

        /// <summary>
        /// Handles DragDrop event and calulates proper position of cell in panel 
        /// from mouse coordinates )
        /// </summary>
        /// <param name="sender"> sender of event</param>
        /// <param name="e"> event arguments </param>
        private void Form_DragDrop(object sender, DragEventArgs e)
        {
            int xOffset = 0;
            int yOffset = 0;
            Point startingPoint = this.PointToScreen(this.DisplayRectangle.Location);

            foreach (ColumnStyle cstyle in this.ColumnStyles)
            {
                int minx = (xOffset) * (int)columnWidth + startingPoint.X;
                int maxx = (xOffset + 1) * (int)columnWidth + startingPoint.X;

                if (e.X >= minx && e.X <= maxx)
                {
                    foreach (RowStyle rstyle in this.RowStyles)
                    {
                        int miny = (yOffset) * (int)rowHeight + startingPoint.Y;
                        int maxy = (yOffset + 1) * (int)rowHeight + startingPoint.Y;

                        if (e.Y >= miny && e.Y <= maxy)
                        {
                            break;
                        }
                        else
                        {
                            yOffset++;
                        }
                    }
                    break;
                }
                else
                {
                    xOffset++;
                }
            }

            int row = yOffset;
            int col = xOffset;

            string controlType = (string)e.Data.GetData(typeof(string));
            BaseControl bc;
            //if there is no control in the cell, then add it 
            if (null == formCContainer.GetControl(row, col))
            {

                Control ctrl = GControlFactory.Instance.GetControl(controlType);
                this.Controls.Add(ctrl, col, row);

                if (null == (bc = BLogicControlFactory.Instance.GetLogicControl(ctrl.GetType())))
                {
                    MessageBox.Show("Not supported control!", "error", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    return;
                }

                formCContainer.AddControl(row, col, bc);
            }

        }

        /// <summary>
        /// Handles mouse clicked event
        /// </summary>
        /// <param name="sender"> sender of the event </param>
        /// <param name="e"> MouseEventArgs to get location of mouse pointer</param>
        private void Form_CellClicked(object sender, MouseEventArgs e)
        {
            int row = 0;
            int col = 0;

            if (true == GetColAndRow(ref row, ref col, e.Location))
            {
                selectedRow = row;
                selectedColumn = col;

                fephEvent(formCContainer.GetControl(row, col));

                this.Refresh();
            }
        }


        /// <summary>
        /// handles cellPaint event
        /// </summary>
        /// <param name="sender"> sender of the event</param>
        /// <param name="e">args for getting graphics</param>
        private void Form_CellPaint(object sender, TableLayoutCellPaintEventArgs e)
        {
            if (e.Row == selectedRow && e.Column == selectedColumn)
            {
                Brush mybrush = System.Drawing.Brushes.DarkRed;
                e.Graphics.FillRectangle(mybrush, e.CellBounds);
            }
        }

        #endregion

    }
}
